#include "pixelType.h"
#include "unsorted.h"

class Region{
	public:
	Region();
	void print();
	Region &operator = ( Region& );
	bool operator < (const Region& );
	bool operator <= (const Region& );
	bool operator == (const Region& );
	void setSize( int );
	void setOrientation( int );
	void setEcc( int );
	void setInt( int );
	void writeToImage( ImageType &, ImageType & );
	void calcOrientation();
	void calcEccentricity();
	void calcIntensity(ImageType );
	void calcCentroid();
	bool orCompare( Region, Region );
	bool eccCompare( Region, Region);
	bool intCompare( Region, Region );
	
	
	
	template<class ItemType>
	friend class NodeType;
   
	template<class ItemType>
	friend class SortedType;
   
	template<class ItemType>
	friend class UnsortedType;
   
   // List of pixels
	UnsortedType<PixelType> pixel_list;
   
	private:
	// GEOMETRIC PROPERTIES
	PixelType centroid;
	int size;
	float orientation;
	float eccentricity;
	// INENSITY PROPERTIES
	int mean;
	int min;
	int max;

	float lambda_min, lambda_max, axes_max, axes_min;
};

//////////////////////////////// Region Implemntation /////////////////////////////////////
Region::Region()
{
	centroid.x = 0;
	centroid.y = 0;
	
	size = 0;
	orientation = 0;
	eccentricity = 0; 
	mean = 0;
	min = 0;
	max = 0;

}

void Region::print()
{
	int x, y;
	PixelType dummy;
	cout << "Geometric Properties:" << endl;
	cout << "  Centroid: ";
		centroid.print();
	cout << endl;
	cout << "  Size: " << size << endl;
	cout << "  Orientation: " << orientation << endl;
	cout << "  Eccentricity: " << eccentricity << endl;
	cout << "Photometric Properties:" << endl;
	cout << "  Mean Intensity: " << mean << endl;
	cout << "  Minimum Intensity: " << min << endl;
	cout << "  Maximum Intensity: " << max << endl;
	
}

Region &Region:: operator = ( Region &rhs )
{
	PixelType dummy;
	
	if( this != &rhs )
	{
		(*this).size = rhs.size;
		(*this).orientation = rhs.orientation;
		(*this).eccentricity = rhs.eccentricity;
		(*this).mean = rhs.mean;
		(*this).min = rhs.min;
		(*this).max = rhs.max;
		
		// Copy Pixels
		rhs.pixel_list.ResetList();
		pixel_list.MakeEmpty();
		
		while( !rhs.pixel_list.IsLastItem() )
		{
			rhs.pixel_list.GetNextItem( dummy );
			pixel_list.InsertItem( dummy );

		}
		return *this;
	}
}

void Region::calcCentroid()
{
	PixelType temp;
	centroid.x = 0;
	centroid.y = 0;
	pixel_list.ResetList();
	
	while( !pixel_list.IsLastItem() )
	{
	
		cout << "PREV" << endl;
		pixel_list.GetNextItem( temp );
		cout << "GET NEXT" << endl;
		centroid.x += temp.x;
		centroid.y += temp.y;
	}
	centroid.x /= pixel_list.LengthIs();
	size = pixel_list.LengthIs();
}

void Region::calcOrientation()
{
	int moment_2_x = 0;
	int moment_1_1 = 0;
	PixelType temp;
	
	if( eccentricity != 0 )
	{
		pixel_list.ResetList();
		while( !pixel_list.IsLastItem() )
		{
			pixel_list.GetNextItem( temp );
			
			moment_2_x += (( temp.x - centroid.x )*( temp.x - centroid.x ));
			moment_1_1 += (temp.x - centroid.x)*(temp.y - centroid.y);
		}
		
		orientation = atan((lambda_max - moment_2_x)/moment_1_1 );
	}
}

void Region::calcEccentricity()
{
	// Variables for Moment calclation
	PixelType moment_2;
	PixelType temp;
	float square_root;
	int moment_1_1 = 0;
	
	moment_2.x = 0;
	moment_2.y = 0;
	if( centroid.x != 0 )
	{
		pixel_list.ResetList();
		while( !pixel_list.IsLastItem() )
		{
			pixel_list.GetNextItem( temp );
			moment_2.x += (( temp.x - centroid.x )*( temp.x - centroid.x ));
			moment_2.y += (( temp.y - centroid.y )*( temp.y - centroid.y ));
			moment_1_1 += (temp.x - centroid.x)*(temp.y - centroid.y);
		}
		
		square_root = sqrt( (moment_2.x)*(moment_2.x) + (moment_2.y)*(moment_2.y) - 
										2*(moment_2.x)*(moment_2.y) + 4 * (moment_1_1)*(moment_1_1));
		
		lambda_max = 0.5 * (moment_2.x + moment_2.y) + 0.5 * square_root;
		lambda_min = 0.5 * (moment_2.x + moment_2.y) - 0.5 * square_root;
		
		axes_max = sqrt( lambda_max / pixel_list.LengthIs() );
		axes_min = sqrt( lambda_min / pixel_list.LengthIs() );
		
		eccentricity = (axes_max  / axes_min);
	}
}
/*
   int mean;
   int min;
   int max;
*/
void Region::calcIntensity( ImageType rhs)
{
	mean = 0;
	min = 0;
	max = 0;
	int imagevalue;
	PixelType temp;
	pixel_list.ResetList();
	while( !pixel_list.IsLastItem() )
	{
		pixel_list.GetNextItem( temp );
		rhs.getPixelVal( temp.x, temp.y, imagevalue );
		mean += imagevalue;
		if( mean < imagevalue )
		{
			max = imagevalue;
		}
		if( min > imagevalue )
		{
			min = imagevalue;
		}
	}
	
	mean /= pixel_list.LengthIs();
}

bool Region::operator < (const Region &rhs )
{
	return ( size < rhs.size );
}

bool Region::operator <= (const Region &rhs )
{
	return ( size <= rhs.size );
}

bool Region::operator == (const Region& rhs)
{
	return( size == rhs.size );
}

void Region::setSize( int a )
{
	size = a;
}

void Region::setOrientation( int a )
{
	orientation = a;
}

void Region::setEcc( int a )
{
	eccentricity = a;
}

void Region::setInt( int a )
{
	mean = a;
}

bool Region::orCompare( Region a, Region b)
{
	if( a.orientation < b.orientation )
	{
		return true;
	}
	else
	return false;
}

bool Region::eccCompare( Region a, Region b)
{
	if( a.eccentricity < b.eccentricity )
	{
		return true;
	}
	else
	return false;
}

bool Region::intCompare( Region a, Region b )
{
	if( a.mean < b.mean )
	{
		return true;
	}
	else
	return false;
}

void Region::writeToImage( ImageType &source, ImageType &dest )
{
	PixelType temp;
	int tempColor;
	
	pixel_list.ResetList();
	
	while( !pixel_list.IsLastItem() )
	{
		pixel_list.GetNextItem( temp );
		source.getPixelVal( (*pixel_list.listData).info.x, 
										(*pixel_list.listData).info.y, tempColor );
		dest.setPixelVal( (*pixel_list.listData).info.x, 
										(*pixel_list.listData).info.y, tempColor );
	}
}